//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <fcntl.h>

#include <aura.h>
#include <auraplus.h>
#include <aura_wchar.h>

AURA_API AuraSystem_GetTime(
        /* [out] */ Aura_SystemTime * pTime)
{
    struct timeval tv;
    if(-1 == gettimeofday(&tv, AURA_NULL)){
        return AURA_E_FAIL;
    }

    pTime->seconds = (Aura_Int32)tv.tv_sec;
    pTime->microseconds = (Aura_Int32)tv.tv_usec;

    return AURA_NOERROR;
}

AURA_API AuraSystem_SetTime(
        /* [in] */ Aura_SystemTime * pTime)
{
    struct timeval tv;
    tv.tv_sec = (long)pTime->seconds;
    tv.tv_usec = (long)pTime->microseconds;

    if(-1 == settimeofday(&tv, AURA_NULL)){
        return AURA_E_FAIL;
    }

    return AURA_NOERROR;
}

struct timeval g_tvStartTime;

AURA_API AuraSystem_GetElapsedTime(
        /* [out] */ Aura_Millisecond * pTime)
{
    struct timeval current_time;

    assert(AURA_NULL != pTime);

    gettimeofday(&current_time, AURA_NULL);

    *pTime = (current_time.tv_sec - g_tvStartTime.tv_sec) * 1000 +
           (current_time.tv_usec - g_tvStartTime.tv_usec) / 1000;

    return AURA_NOERROR;
}

AURA_API AuraSystem_GetIdleTime(
        /* [out] */ Aura_Millisecond * pTime)
{
    return AURA_E_NOT_IMPLEMENTED;
}

//BUGBUG:May use Aura_UInt32 should be better.
AURA_API AuraSystem_GetTickCount(
        /* [out] */ Aura_Int64 * pTicks)
{
    return AuraSystem_GetElapsedTime((Aura_Millisecond *)pTicks);
}

AURA_API AuraSystem_GetLoopCountPerMicrosecond(
        /* [out] */ Aura_UInt32 * pLoopCount)
{
    Aura_Int32 u = 0, testCount = 1000;
    struct timeval tvStartTime;
    struct timeval tvEndTime;
    long lUsec;

    assert(AURA_NULL != pLoopCount);

    gettimeofday(&tvStartTime, AURA_NULL);
    while (u < testCount) {
        u++;
    }
    gettimeofday(&tvEndTime, AURA_NULL);

    lUsec = (tvEndTime.tv_sec - tvStartTime.tv_sec)*1000000
        + (tvEndTime.tv_usec - tvStartTime.tv_usec);

    *pLoopCount = testCount / lUsec;

    return AURA_NOERROR;
}


//BUGBUG:May use Aura_UInt32 should be better.
AURA_API AuraSystem_GetMemorySizes(
        /* [out] */ Aura_Int32 * pTotalPhysicalMemorySize,
        /* [out] */ Aura_Int32 * pAvailablePhysicalMemorySize)
{
    FILE *iFd;
    char *pLine = AURA_NULL;
    ssize_t iReadSize = 0;
    size_t iLen = 0;
    int i;

    Aura_UInt32 uTotalMem = 0;
    Aura_UInt32 uUsedMem = 0;
    Aura_UInt32 uFreeMem = 0;
    Aura_UInt32 uSharedMem = 0;
    Aura_UInt32 uBuffersMem = 0;
    Aura_UInt32 uCachedMem = 0;

    iFd = fopen("/proc/meminfo", "r");
    if(AURA_NULL == iFd){
        PERROR("Error: Get Memory Size failed! errno%d. \
        file:%s. line:%d. \n",
        errno, __FILE__, __LINE__);
        return AURA_E_INVALID_OPERATION;
    }

    for(i = 0; i < 2; i++){
        if(AURA_NULL != pLine){
            free(pLine);
            iLen = 0;
        }
        iReadSize = getline(&pLine, &iLen, iFd);
        if(-1 == iReadSize){
            PERROR("Error: Get Memory Size failed! errno%d. \
            file:%s. line:%d. \n",
            errno, __FILE__, __LINE__);
            fclose(iFd);
            return AURA_E_INVALID_OPERATION;
        }
    }

    sscanf(pLine, "Mem:  %d %d %d %d %d %d\n",
            &uTotalMem,
            &uUsedMem,
            &uFreeMem,
            &uSharedMem,
            &uBuffersMem,
            &uCachedMem);

    PTRACE("Mem:  Total:%d, Used:%d, Free:%d, Shared:%d, Buffers:%d, Cached:%d.\n",
            uTotalMem,
            uUsedMem,
            uFreeMem,
            uSharedMem,
            uBuffersMem,
            uCachedMem);

    if(AURA_NULL != pTotalPhysicalMemorySize){
        *pTotalPhysicalMemorySize = (Aura_Int32)uTotalMem;
    }

    if(AURA_NULL != pAvailablePhysicalMemorySize){
        *pAvailablePhysicalMemorySize = (Aura_Int32)uFreeMem;
    }


    if(AURA_NULL != pLine){
        free(pLine);
    }
    fclose(iFd);

    return AURA_NOERROR;
}

AURA_API AuraSystem_ErrorPrint(
        /* [in] */ Aura_PWChar wstr)
{

    assert(wstr && wstr[0] != 0);

    int len=Aura_Wcslen(wstr);
    wchar_t *lwstr = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
    if(!lwstr) return AURA_E_OUT_OF_MEMORY;
    Aura_PWchar_to_Pwchar_t(wstr,lwstr);
    wprintf(L"%S", lwstr);
    free (lwstr);
    return AURA_NOERROR;
}

AURA_API AuraSystem_TryWaitForAnyEvent(
        /* [in] */ Aura_Int32 nCount,
        /* [in] */ const Aura_Handle * pEvents,
        /* [in] */ Aura_Int32 msTimeout,
        /* [out] */ Aura_WaitResult * pResult,
        /* [out] */ Aura_Int32 * pIndex,
        /* [out] */ Aura_EventState * pState)
{
    return AURA_NOERROR;
}
